'''
Created on 11/05/2013

@author: jean
'''
from . import ensureParams, jsonifiedview
from decimal import Decimal
from flask import request
from pm import app
from pm.database import db
from pm.models.Fases import Fases
from pm.models.HistorialDetalle import HistorialDetalle
from pm.models.HistorialItem import HistorialItem
from pm.models.Items import Items, crearNombreItem
from pm.models.Proyectos import Proyectos
from pm.models.Relaciones import Relaciones
from pm.models.Archivos import Archivos
from pm.views.MetodosRelacionesViews import getHijos, recorrerAdelante, \
    tieneCiclo
from sqlalchemy import or_
from sqlalchemy.orm.exc import NoResultFound
from pm.models.AtributoItem import AtributoItem
from pm.models.Atributos import Atributos

@app.route('/items/listaritems', methods=['GET', 'POST']) 
@jsonifiedview
def listarItemsByFase():
    """
        Lista los items de una fase
        @param  id_fase: el id de la fase del que se quieren listar los items
    """
    params = {'GET':request.args, 'POST':request.form}[request.method]
    queryItems = Items.query.filter(Items.id_fase == params['id_fase'])
    queryItems = queryItems.filter(Items.nombre.like('%' + params['nombre'] + '%')) if 'nombre' in params else queryItems
    return queryItems.order_by(Items.id_item).all()

@app.route('/items/crear', methods=['GET', 'POST']) 
@jsonifiedview
def crearItem():
    """
        Crea un nuevo tipo de item
        @param id_fase: el id de la fase del que se quieren listar los items
        @param id_tipo_item: el tipo del item
        @param complejidad: la complejidad del item
    """
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  ={}
    
    if not ensureParams(params, ['id_tipo_item', 'id_fase', 'complejidad', 'descripcion', 'observacion', 'prioridad','costo']): 
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    fase = Fases.query.filter(Fases.id_fase == params['id_fase']).one()
    proyecto = Proyectos.query.filter(Proyectos.id_proyecto==fase.id_proyecto).one()
    if proyecto.estado==1:    
        response ={"success" : False , "msg" : "El proyecto aun no ha iniciado"} 
        return response
    if fase.estado !=1 and fase.estado != 2:
        response ={"success" : False , "msg" : "La fase no se encuentra en el estado inicial ni desarrollo"} 
        return response
    try:
        nombre = crearNombreItem(fase.id_proyecto, fase.posicion, fase.cantidad_items + 1)
        proyectos = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
        fasesCreadas = Fases.query.filter(Fases.id_proyecto == proyectos.id_proyecto).filter(Fases.activo == True).all()
        if len (fasesCreadas) != proyectos.cantidad_fases:
            response ={"success" : False , "msg" : "Las fases de este proyecto no se encuentran definidas"} 
            return response
        if fase.posicion > 1:
            try:
                faseAnterior = Fases.query.filter(Fases.id_proyecto == fase.id_proyecto).filter(Fases.posicion == fase.posicion -1).one()
                if faseAnterior.estado != 3 and faseAnterior.estado!= 2:
                    response ={"success" : False , "msg" : "La fase anterior no se encuentra en estado desarrollo o completa"} 
                    return response
            except NoResultFound:
                response ={"success" : False , "msg" : "La fase anterior no se ha creado"} 
                return response   
        item = Items (fase.cantidad_items + 1, nombre,1, params['id_tipo_item'],params['id_fase'], 1, params['complejidad'], params['descripcion'], params['observacion'], params['prioridad'], None, params['costo'])
        db.session.add(item)
        db.session.commit()
        fase.cantidad_items = fase.cantidad_items + 1
        proyectos.complejidad = proyectos.complejidad + item.complejidad
        db.session.commit()
        historialItem= HistorialItem(item.id_item,item.numero, item.nombre, item.estado, item.id_tipo_item, item.id_fase, item.version, item.complejidad,item.descripcion, item.observacion, item.prioridad, None,item.costo) 
        db.session.add(historialItem)
        db.session.commit()
        response = {"success" : True , "msg" : "Creacion Exitosa"}
        return response
    except Exception,e:
        db.session.rollback()
        response={"success" : False , "msg" : "Error en la Base de Datos"}
        return response

@app.route('/items/modificar', methods=['GET', 'POST']) 
@jsonifiedview
def modificarItem():
    """
        Crea un nuevo tipo de item
        @param id_fase: el id de la fase del que se quieren listar los items
        @param id_tipo_itidem: el tipo del item
        @param complejidad: la complejidad del item
    """
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  ={}
    
    if not ensureParams(params, ['id_tipo_item', 'complejidad', 'descripcion', 'observacion', 'prioridad','costo']): 
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    try:
        item = Items.query.filter(Items.id_item == params['id_item']).one()
        if item.estado != 1 and item.estado!=4:
            response = {"success" : False , "msg" : "Si desea modificar el item, desapruebe el item o realize una solicitud de cambio"} 
            return response
        complejidad = int(str(params['complejidad']))
        
        fase = Fases.query.filter(Fases.id_fase== item.id_fase).one()
        if item.complejidad < complejidad:
            proyectos = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
            proyectos.complejidad = (proyectos.complejidad - item.complejidad) + complejidad
        
        elif item.complejidad >complejidad :
            proyectos = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
            proyectos.complejidad = (proyectos.complejidad - item.complejidad) + complejidad
        item= Items.query.filter(Items.id_item == params['id_item']).one()
        historialItemActual = HistorialItem.query.filter(HistorialItem.id_item == item.id_item).filter(HistorialItem.version == item.version).one()
        versionActual= item.version + 1
        item.query.filter(Items.id_item == params['id_item']).update({'id_tipo_item': params['id_tipo_item'],'descripcion': params['descripcion'], 'prioridad': params['prioridad'], 'complejidad': params['complejidad'], 'observacion': params['observacion'],'version': versionActual,'costo':params['costo']})
        db.session.commit()
        historialItem = HistorialItem(item.id_item,item.numero, item.nombre, item.estado, item.id_tipo_item, item.id_fase, item.version, item.complejidad,item.descripcion, item.observacion, item.prioridad, None,item.costo) 
        db.session.add(historialItem)
        db.session.commit()
        historialDetalle= HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemActual.id_historial_item).all()
        for hd in historialDetalle:
            historialDetalleNuevo = HistorialDetalle(hd.id_relacion,historialItem.id_historial_item,hd.estado_relacion)
            db.session.add(historialDetalleNuevo)
            db.session.commit()
        
        versionAnterior = item.version-1
        archivos = Archivos.query.filter(Archivos.id_item == item.id_item).filter(Archivos.version_item == versionAnterior).all()
        for a in archivos:
            archivoNuevo = Archivos(a.nombre_archivo,a.tipo, a.id_item, a.archivo, a.activo, item.version)
            db.session.add(archivoNuevo)
            db.session.commit()
        
        response = {"success" : True , "msg" : "Actualizacion Exitosa"} 
        return response
    except Exception, e:
        db.session.rollback()
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response

@app.route('/items/aprobar', methods=['GET', 'POST']) 
@jsonifiedview
def aprobarItem():
    
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  ={}
    
    if not ensureParams(params, ['id_item']): 
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    item=Items.query.filter(Items.id_item== params['id_item']).one()
    
    if item.estado != 1  and item.estado!=4 and item.estado!=5:
        response = {"success" : False , "msg" : "El item no se encuentra en estado desaprobado"} 
        return response
    if item.estado==5 and item.id_linea_base!=None:
        response = {"success" : False , "msg" : "El item no se puede aprobar porque esta dentro de una linea base"} 
        return response
    try:
        item.estado = 2
        db.session.commit()
        response = {"success" : True , "msg" : "Aprobacion Exitosa"} 
        return response
    except Exception, e:
        db.session.rollback()
        response = {"success" : False , "msg" : "Error en la base de datos"} 
        return response

@app.route('/items/desaprobar', methods=['GET', 'POST']) 
@jsonifiedview
def desaprobarItem():
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  ={}
    
    if not ensureParams(params, ['id_item']): 
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    if not ensureParams(params, ['id_item']): 
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    item=Items.query.filter(Items.id_item== params['id_item']).one()
    
    if item.estado != 2 and item.estado != 5:
        response = {"success" : False , "msg" : "El item no se puede desaprobar"} 
        return response
    if item.estado==5 and item.id_linea_base!=None:
        response = {"success" : False , "msg" : "El item no se puede desaprobar porque esta dentro de una linea base"} 
        return response
    try:
        item.estado = 1
        db.session.commit()
        response = {"success" : True , "msg" : "Desaprobacion Exitosa"} 
        return response
    except Exception, e:
        db.session.rollback()
        response = {"success" : False , "msg" : "Error en la base de datos"} 
        return response
    
@app.route('/items/versionar', methods=['GET', 'POST']) 
@jsonifiedview
def versionarItem():
    
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  ={}
    
    if not ensureParams(params, ['id_item', 'version']): 
        response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    item = Items.query.filter(Items.id_item == params['id_item']).one()
    
    if item.estado !=1:
        response = {"success" : False , "msg" : "El item se debe encontrar en estado desaprobado"} 
        return response
    try:
        if item.version == int(str(params['version'])):
            response = {"success" : False , "msg" : "La version seleccionada es la misma que posee actualmente"} 
            return response
            
        historialItem = HistorialItem.query.filter(HistorialItem.id_item == params['id_item']).filter(HistorialItem.version == params['version']).one()
        item.query.filter(Items.id_item == params['id_item']).update({'estado': historialItem.estado, 'id_tipo_item': historialItem.id_tipo_item, 'version': item.version + 1, 'complejidad': historialItem.complejidad,'descripcion': historialItem.descripcion, 'observacion': historialItem.observacion, 'prioridad': historialItem.prioridad,'costo':historialItem.costo})
        db.session.commit()
        historialItemAux= HistorialItem(historialItem.id_item, historialItem.numero, historialItem.nombre, historialItem.estado,historialItem.id_tipo_item,historialItem.id_fase, item.version, historialItem.complejidad, historialItem.descripcion, historialItem.observacion, historialItem.prioridad, historialItem.id_linea_base,historialItem.costo)
        db.session.add(historialItemAux)
        db.session.commit()
        response = {"success" : True , "msg" : "El item fue versionado correctamente"} 
        return response

    except Exception, e:
        db.session.rollback()
        response = {"success" : False , "msg" : "Error en la Base de Datos"} 
        return response
    
@app.route('/items/listarversionesporitem', methods=['GET', 'POST']) 
@jsonifiedview
def getVersionesPorItem():
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  =[]
    
    if not ensureParams(params, ['id_item']): 
        response = [] 
        return response
    
    historialItem= HistorialItem.query.filter(HistorialItem.id_item == params['id_item']).all()
    for hi in historialItem:
        response.append(hi) 
    
    return response

@app.route('/items/eliminaritem', methods=['GET', 'POST']) 
@jsonifiedview
def eliminarItem():
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = {}
    
    if not ensureParams(params, ['id_item']): 
        response = response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    item= Items.query.filter(Items.id_item == params['id_item']).one()
        
    if item.estado == 6:
        response = {"success" : False , "msg" : "El item se encuentra actualmente en estado eliminado"} 
        return response
        
    if item.estado == 3:
        response = {"success" : False , "msg" : "El item se encuentra actualmente en estado bloqueado"} 
        return response
    
    if item.estado == 5:
        response = {"success" : False , "msg" : "El item se encuentra actualmente en estado revision-bloq"} 
        return response
    
    if item.estado == 2:
        response = {"success" : False , "msg" : "El item se encuentra actualmente en estado Aprobado"} 
        return response
    try:
        #visitadoAdelante = [] 
        #recorrerAdelante(params['id_item'],visitadoAdelante)
        existeRelacion= False
        rel = Relaciones.query.filter(Relaciones.id_origen==params['id_item']).all()
        for r in rel:
            if(r.activo==True):
                existeRelacion=True    
            
        if existeRelacion == True:       
            response = {"success" : False , "msg" : "Existen conflictos en la relacion con un hijo o sucesor. \nSe deben eliminar todas las relaciones activas con este item"} 
            return response
        
        historialItemActual = HistorialItem.query.filter(HistorialItem.id_item == item.id_item).filter(HistorialItem.version == item.version).one()
        
        historialItem = HistorialItem(item.id_item,item.numero, item.nombre, item.estado, item.id_tipo_item, item.id_fase, item.version+1, item.complejidad,item.descripcion, item.observacion, item.prioridad, None,item.costo) 
        db.session.add(historialItem)
        db.session.commit()
            
        historialDetalle= HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemActual.id_historial_item).all()
        for hd in historialDetalle:
            historialDetalleNuevo = HistorialDetalle(hd.id_relacion,historialItem.id_historial_item,hd.estado_relacion)
            db.session.add(historialDetalleNuevo)
            db.session.commit()        
            
        itemAux = Items.query.filter(Items.id_item == params['id_item']).one()
        item.query.filter(Items.id_item == params['id_item']).update({'estado': 6,'version':itemAux.version+1})
        
        relaciones= Relaciones.query.filter(or_(Relaciones.id_origen ==item.id_item,Relaciones.id_destino ==item.id_item)).update({'activo': False})
        fase= Fases.query.filter(Fases.id_fase== item.id_fase).one()
        fase.query.filter(Fases.id_fase== item.id_fase).update({'cantidad_items': fase.cantidad_items - 1})
        proyecto = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
        proyecto.complejidad = proyecto.complejidad - item.complejidad 
        db.session.commit()
        response = {"success" : True , "msg" : "Eliminacion Exitosa"} 
        return response
    except Exception, e:
        db.session.rollback()
        response = response = {"success" : False , "msg" : "Error en la Base de Datos"} 
        return response
        
    return response


@app.route('/items/reviviritem', methods=['GET', 'POST']) 
@jsonifiedview
def revivirItem():
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = {}
    
    if not ensureParams(params, ['id_item']): 
        response = response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    
    item= Items.query.filter(Items.id_item == params['id_item']).one()
    
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = {}
    
    if item.estado != 6:
        response = {"success" : False , "msg" : "El item no se encuentra en estado eliminado"} 
        return response
    
    item= Items.query.filter(Items.id_item == params['id_item']).one()
    
    try:        
        item.query.filter(Items.id_item == params['id_item']).update({'estado': 1})
        fase= Fases.query.filter(Fases.id_fase== item.id_fase).one()
        fase.query.filter(Fases.id_fase== item.id_fase).update({'cantidad_items': fase.cantidad_items + 1})
        proyecto = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
        proyecto.complejidad = proyecto.complejidad + item.complejidad 
        db.session.commit()
        response = {"success" : True , "msg" : "Se revivio exitosamente el item!!"} 
        return response
    except Exception, e:
        db.session.rollback()
        response = response = {"success" : False , "msg" : "Error en la Base de Datos"} 
        return response
    
@app.route('/items/revertir-v2', methods=['GET', 'POST']) 
@jsonifiedview
def revertirItemV2():
    """
    Metodo que revierte un item a una version anterior 
    @param id_historial_item: el id del item al cual se desea volver
    """
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = {}
    
    if not ensureParams(params, ['id_historial_item']): 
        response = response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    try: 
        listRelaciones =[]
        
        historialItem = HistorialItem.query.filter(HistorialItem.id_historial_item == params['id_historial_item']).one()
        historialDetalle = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItem.id_historial_item).all()
        for hd in historialDetalle:
            relacion = Relaciones.query.filter(Relaciones.id_relacion == hr.id_relacion).first()
            listRelaciones.append(relacion)
        
        item = Items.query.filter(Items.id_item == historialItem.id_item).one()
        reldestinos = item.destinos
        relorigenes = item.origenes
        
        fase = Fases.query.filter(Fases.id_fase == item.id_fase).one()
        proyecto = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
        
        proyecto.complejidad = proyecto.complejidad - item.complejidad
        proyecto.complejidad = proyecto.complejidad + historialItem.complejidad
        db.session.merge()
        
        ListaRelacionesOrigen = []
        ListaRelacionesDestino = []
        
        if reldestinos:
            for reld in reldestinos:
                if reld.activo == True:
                    ListaRelacionesOrigen.append(reld)
                    
        if relorigenes:
            for relo in relorigenes:
                if relo.activo == True:
                    ListaRelacionesDestino.append(relo)
    
        historialNuevo = HistorialItem(item.id_item, item.numero, item.nombre,item.estado, item.id_tipo_item,item.id_fase,item.version + 1, item.complejidad, item.descripcion, item.observacion, item.prioridad, item.id_linea_base)
        db.session.add(historialNuevo)
        #db.session.commit()
        #detalles = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItem.id_historial_item).all() 
       
        for orig in ListaRelacionesOrigen:
            detalle = HistorialDetalle(orig.id_relacion, historialNuevo.id_historial_item)
            db.session.add(detalle)
        
            itemMarcar = Item.query.filter(Item.id_item == orig.id_destino).one()
            LBMarcar= LineaBase.query.filter(LineaBase.id_linea_Base == itemMarcar.id_linea_base).first()
            if LBMarcar.estado != 4:
                if LBMarcar != None:
                    listaLB= Items.query.filter(Items.id_linea_base== LBMarcar.id_linea_base).all()
                    if LBMarcar.estado ==1  or LBMarcar.estado == 3:
                        for itemLB in listaLB:
                            itemLB.estado = 5
                            db.session.merge(itemLB)
                        LBMarcar.estado = 3
                else:
                            
                    for itemLB in listaLB:
                        itemLB.estado = 4
                        db.session.merge(itemLB)
            else:
                    itemMarcar.estado = 2
                    
                    db.session.merge(itemMarcar)
                    
        for dest in ListaRelacionesDestino:
            detalle = HistorialDetalle(dest.id_relacion, historialNuevo.id_historial_item)
            db.session.add(detalle)
        
            itemMarcar = Item.query.filter(Item.id_item == dest.id_origen).one()
            LBMarcar= LineaBase.query.filter(LineaBase.id_linea_Base == itemMarcar.id_item).first()
            if LBMarcar.estado != 4:
                if LBMarcar != None:
                    listaLB= Items.query.filter(Items.id_linea_base== LBMarcar.id_linea_base).all()
                    if LBMarcar.estado ==1  or LBMarcar.estado == 3:
                        for itemLB in listaLB:
                            itemLB.estado = 5
                            db.session.merge(itemLB)
                        LBMarcar.estado = 3
                    else:
                            
                        for itemLB in listaLB:
                            itemLB.estado = 4
                            db.session.merge(itemLB)
            else:
                    itemMarcar.estado = 2
                    
                    db.session.merge(itemMarcar)
    
        item.descripcion = historialItem.descripcion
        item.complejidad = historialItem.complejidad
        item.observacion = historialItem.observacion
        
        item.version = item.version + 1
        itemLBase = LineasBases.query.filter(LineasBases.id_linea_base == item.id_linea_base).first()
        
        if itemLBase != None:
            if itemLBase.estado == 1 or itemLBase.estado == 3:
                itemLBase.estado = 3
                item.estado = 4
            else:            
                item.estado = 5
        else:
            item.estado = 5
            
        itemFase = Fases.query.filter(item.id_fase).first()
        itemFase.estado = 2
        ListaOrigen = []
        ListaDestino = []
        
        for relacionDetalle in listRelaciones:
            relacion = Relaciones.query.filter(Relaciones.id_relacion==relacionDetalle.id_relacion).first()
            if relacion.activo == True:
                if relacion.tipo == 1:
                    origenRelacion = Items.query.filter(Items.id_item == relacion.id_origen)
                    destinoRelacion = Items.query.filter(Items.id_item ==relacion.id_destino)
                    if tieneCiclo(getHijos(destinoRelacion.id_item), origenRelacion.id_relacion):
                        db.session.rollback()
                        return {'success': False, 'msg':'Una de las relaciones del item genera un ciclo.', 'id_item':id_item }
                else:
                    relacion.estado = True
                    db.session.merge(relacion)
                    
            if relacion.id_origen == item.id_item:
                ListaOrigen.append(relacion) 
                itemMarcar = Items.query.filter(Items.id_item == relacion.id_destino).first()
                LBMarcar = LineasBases.query.filter(LineasBases.id_linea_base == itemMarcar.id_linea_base).first()
                
                if itemMarcar.estado != 6:
                    if LBMarcar != None:
                        listaItemsLBO = Items.query.filter(Items.id_linea_base == LBMarcar.id_linea_base).all()
                        if LBMarcar.estado == 1 or LBMarcar.estado == 3:
                            for itemLBO in listaItemsLBO:
                                itemLBO.estado = 5
                                db.session.merge(itemLBO)
                                    
                                LBMarcar.estado = 3
                        else:
                            for itemLBO in listaItemsLBO:
                                itemLBO.estado = 4
                                db.session.merge(itemLBO)
                                    
                        db.session.merge(LBMarcar)
                    else:
                        itemMarcar.estado = 5
                    
                    db.session.merge(itemMarcar)
                    
            if relacion.id_destino == item.id_item:
                ListaDestino.append(relacion)
                itemMarcar = Items.query.filter(Items.id_item == relacion.id_origen)
                LBMarcar = LineasBases.getByIdLineaBase(itemMarcar.id_linea_base)
                if itemMarcar.estado != 6:
                    if LBMarcar != None:
                        listaItemsLBD = Items.query.filter(Items.id_linea_base == LBMarcar.id_linea_base).all()
                        if LBMarcar.estado == 1 or LBMarcar.estado == 3:
                            for itemLBD in listaItemsLBD:
                                itemLBD.estado = 5
                                db.session.merge(itemLBD)
                            
                            LBMarcar.estado = 3
                        else:
                            for itemLBD in listaItemsLBD:
                                itemLBD.estado = 4
                                db.session.merge(itemLBD)
                            
                        db.sessiond.merge(LBMarcar)
                    else:
                        itemMarcar.estado = 4
                    db.session.merge(itemMarcar)
        item.origenes = ListaDestino
        item.destinos = ListaOrigen
        
        db.session.merge(item)
        if itemLBase != None:
            db.session.merge(itemLBase)
        if itemFase != None:
            db.session.merge(itemFase)
        db.session.commit()
    except Exception, e: 
        db.session.rollback()
        return {'success': False, 'msg':'Ha ocurrido un error al tratar de revertir el Item.', 'id_item':id_item}
    
    return {'success': True, 'mensaje':'Item revertido a una version anterior, revise los items involucrados en las relaciones.', 'id_item':id_item}


@app.route('/items/revertir', methods=['GET', 'POST']) 
@jsonifiedview
def revertirItem():
    """
    Metodo que revierte un item a una version anterior 
    @param id_historial_item: el id del item al cual se desea volver
    """
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = {}
    
    if not ensureParams(params, ['id_historial_item']): 
        response = response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    try:
        listDetOrigenes = []
        listDetDestinos = []
        
        historialItem = HistorialItem.query.filter(HistorialItem.id_historial_item == params['id_historial_item']).one()
        historialDetalle = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItem.id_historial_item).all()
        
        item = Items.query.filter(Items.id_item == historialItem.id_item).one()
        if item.estado != 1 and item.estado != 2 and item.estado != 4:
            response = response = {"success" : False , "msg" : "El item no puede ser modificado"} 
            return response
        if(item.version ==historialItem.version):
            response = response = {"success" : False , "msg" : "La version actual y la seleccionada es la misma"} 
            return response
        
        historialItemActual = HistorialItem.query.filter(HistorialItem.id_item == item.id_item).filter(HistorialItem.version == item.version).one()
        historialDetalleActual = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item ==historialItemActual.id_historial_item).all()
        for hdac in historialDetalleActual:
            relacionActual = Relaciones.query.filter(Relaciones.id_relacion == hdac.id_relacion).one()
            if relacionActual.activo == True:
                relacionActual.activo = False
                db.session.commit() 
                if relacionActual.id_origen == historialItemActual.id_item:
                    itemDest = Items.query.filter(Items.id_item == relacionActual.id_destino).first()
                    historialItemDest= HistorialItem.query.filter(HistorialItem.id_item == itemDest.id_item).filter(HistorialItem.version == itemDest.version).one()
                    historialItemDetalleDest =HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemDest.id_historial_item).filter(HistorialDetalle.id_relacion == relacionActual.id_relacion).first()
                    historialItemDetalleDest.estado_relacion = False
                    db.session.commit()
                    
                else:
                    
                    itemOri = Items.query.filter(Items.id_item == relacionActual.id_origen).first()
                    historialItemOrig= HistorialItem.query.filter(HistorialItem.id_item == itemOri.id_item).filter(HistorialItem.version == itemOri.version).one()
                    historialItemDetalleOrig =HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemOrig.id_historial_item).filter(HistorialDetalle.id_relacion == relacionActual.id_relacion).first()
                    historialItemDetalleOrig.estado_relacion = False
                    db.session.commit()
        
        fase = Fases.query.filter(Fases.id_fase == item.id_fase).one()
        proyecto = Proyectos.query.filter(Proyectos.id_proyecto == fase.id_proyecto).one()
        proyecto.complejidad = proyecto.complejidad-item.complejidad
        proyecto.complejidad = proyecto.complejidad + historialItem.complejidad
        db.session.commit()
        
        item.estado=  item.estado
        item.id_tipo_item = historialItem.id_tipo_item
        item.version = item.version + 1
        item.complejidad = historialItem.complejidad
        item.descripcion= historialItem.descripcion
        item.observacion=historialItem.observacion
        item.prioridad = historialItem.prioridad
        item.costo = historialItem.costo
        db.session.commit()
        historialItemAux= HistorialItem(historialItem.id_item, historialItem.numero, historialItem.nombre, historialItem.estado,historialItem.id_tipo_item,historialItem.id_fase, item.version, historialItem.complejidad, historialItem.descripcion, historialItem.observacion, historialItem.prioridad, historialItem.id_linea_base,historialItem.costo)
        db.session.add(historialItemAux)
        db.session.commit()
        
        archivos= Archivos.query.filter(Archivos.id_item == item.id_item).filter(Archivos.version_item == historialItem.version).all()
        for a in archivos:
            archivoNuevo = Archivos(a.nombre_archivo, a.tipo, a.id_item,a.archivo,a.activo, item.version)
            db.session.add(archivoNuevo)
            db.session.commit() 
             
        for hd in historialDetalle:
            relacion = Relaciones.query.filter(Relaciones.id_relacion == hd.id_relacion).one()
            historialNuevo = HistorialDetalle(hd.id_relacion,historialItemAux.id_historial_item, hd.estado_relacion)
            db.session.add(historialNuevo)
            db.session.commit()
        
        historialDetalleAux= HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemAux.id_historial_item).all()
        for hda in historialDetalleAux: 
            relacion = Relaciones.query.filter(Relaciones.id_relacion == hda.id_relacion).one()
            if (relacion.id_origen == historialItemAux.id_item):
                listDetDestinos.append(hda)
            else:
                listDetOrigenes.append(hda)

        for ldo in listDetOrigenes:
            relacionAux = Relaciones.query.filter(Relaciones.id_relacion == ldo.id_relacion).one()
            itemOrig =  Items.query.filter(Items.id_item==relacionAux.id_origen).first()
            if relacionAux.tipo == 1:
                if itemOrig.estado  == 2 or itemOrig.estado == 3 or itemOrig.estado == 4:
                    if relacionAux.activo != ldo.estado_relacion:
                        estadoAux = relacionAux.activo
                        relacionAux.activo = ldo.estado_relacion
                        db.session.commit()
                        if tieneCiclo(getHijos(item.id_item), itemOrig.id_item) == None:
                            relacionAux.activo = estadoAux
                            db.session.commit()
                            ldo.estado_relacion = estadoAux
                            db.session.commit()
                            response = response = {"success" : False , "msg" : "Una de las relaciones a revertir causo un ciclo"} 
                            return response
                        else:
                            historialItemOrig = HistorialItem.query.filter(HistorialItem.id_item == itemOrig.id_item).filter(HistorialItem.version == itemOrig.version).one()
                            historialDetOrig = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemOrig.id_historial_item).filter(HistorialDetalle.id_relacion == ldo.id_relacion).one()
                            historialDetOrig.estado_relacion = relacionAux.activo
                            db.session.commit()
                else:
                    response = response = {"success" : False , "msg" : "Un origen de la relacion no esta aprobado"} 
                    ldo.estado_relacion = relacionAux.activo
                    db.session.commit()
                    return response
            else:
                if itemOrig.estado == 3 or itemOrig.estado == 2:
                    if relacionAux.activo != ldo.estado_relacion:
                        estadoAux = relacionAux.activo
                        relacionAux.activo = ldo.estado_relacion
                        db.session.commit()
                        if tieneCiclo(getHijos(item.id_item), itemOrig.id_item) == None:
                            relacionAux.activo = estadoAux
                            db.session.commit()
                            ldo.estado_relacion = estadoAux
                            db.session.commit()
                            response = response = {"success" : False , "msg" : "Una de las relaciones a revertir causo un ciclo"} 
                            return response
                        else:
                            historialItemOrig = HistorialItem.query.filter(HistorialItem.id_item == itemOrig.id_item).filter(HistorialItem.version == itemOrig.version).one()
                            historialDetOrig = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemOrig.id_historial_item).filter(HistorialDetalle.id_relacion == ldo.id_relacion).one()
                            historialDetOrig.estado_relacion = relacionAux.activo
                            db.session.commit()
                else:
                    response = response = {"success" : False , "msg" : "El item no se encuentra en linea Base"}
                    ldo.estado_relacion = relacionAux.activo
                    db.session.commit() 
                    return response  
        for ldd in listDetDestinos:
            relacionAux = Relaciones.query.filter(Relaciones.id_relacion == ldd.id_relacion).one()
            itemDest =  Items.query.filter(Items.id_item==relacionAux.id_destino).first()
            if itemDest.estado == 1 or itemDest.estado == 2 or itemDest.estado == 4 or (itemDest.estado==5 and itemDest.id_linea_base==None):
                if relacionAux.activo != ldd.estado_relacion:
                        estadoAux = relacionAux.activo
                        relacionAux.activo = ldd.estado_relacion
                        db.session.commit()
                        if tieneCiclo(getHijos(itemDest.id_item), item.id_item) == None:
                            relacionAux.activo = estadoAux
                            db.session.commit()
                            ldd.estado_relacion = estadoAux
                            db.session.commit()
                            response = response = {"success" : False , "msg" : "Una de las relaciones a revertir causo un ciclo"} 
                            return response
                        else:
                            historialItemDest = HistorialItem.query.filter(HistorialItem.id_item == itemDest.id_item).filter(HistorialItem.version == itemDest.version).one()
                            historialDetDest = HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemDest.id_historial_item).filter(HistorialDetalle.id_relacion == ldd.id_relacion).one()
                            historialDetDest.estado_relacion = relacionAux.activo
                            db.session.commit()
            else:
                response = response = {"success" : False , "msg" : "El item destino se encuentra en linea Base"} 
                ldd.estado_relacion = relacionAux.activo
                db.session.commit() 
                return response 
                    
        response = response = {"success" : True , "msg" : "Versionamiento exitoso"} 
        return response
    except Exception, e:
        db.session.rollback()
        response = response = {"success" : False , "msg" : "Ups, ha ocurrido un error"} 
        return response
        
@app.route('/items/asignarvaloratributo', methods=['GET', 'POST']) 
@jsonifiedview
def asignarValorAAtributo():
    """
        metodo que asigna el valor de un atributo a un item
        @param id_atributo: el id del atributo al cual se asignara el valor
        @param id_item: el id del item al que se asignara el valor del atributo
        @param tipo_dato: el tipo de dato del valor
        @param valor: el valor del atributo 
    """
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = {}
    
    if not ensureParams(params, ['id_atributo', 'id_item','tipo_dato','valor']): 
        response = response = {"success" : False , "msg" : "Parametros Insuficientes"} 
        return response
    try:
        item= Items.query.filter(Items.id_item == params['id_item']).one()
        historialItemActual = HistorialItem.query.filter(HistorialItem.id_item == item.id_item).filter(HistorialItem.version == item.version).one()
                
        historialItem = HistorialItem(item.id_item,item.numero, item.nombre, item.estado, item.id_tipo_item, item.id_fase, item.version+1, item.complejidad,item.descripcion, item.observacion, item.prioridad, None,item.costo) 
        db.session.add(historialItem)
        db.session.commit()

        historialDetalle= HistorialDetalle.query.filter(HistorialDetalle.id_historial_item == historialItemActual.id_historial_item).all()
        for hd in historialDetalle:
            historialDetalleNuevo = HistorialDetalle(hd.id_relacion,historialItem.id_historial_item,hd.estado_relacion)
            db.session.add(historialDetalleNuevo)
            db.session.commit()     
        item.version = item.version +1
        db.session.commit()
        """
            Copiamos los archivos de la version anterior
        """
        versionAnterior = item.version - 1
        archivos = Archivos.query.filter(Archivos.id_item == item.id_item).filter(Archivos.version_item == versionAnterior).all()
        for a in archivos:
            archivoNuevo = Archivos(a.nombre_archivo,a.tipo, a.id_item, a.archivo, a.activo, item.version)
            db.session.add(archivoNuevo)
            db.session.commit()
        atributoItem= AtributoItem(params['id_atributo'], item.id_item, item.version, params['tipo_dato'],params['valor'])
        db.session.add(atributoItem)
        db.session.commit()
        
        response = {"success" : True , "msg" : "Asignacion de valor exitosa"} 
        return response
    
    except Exception,e:
        response = {"success" : False , "msg" : "Ups, ha ocurrido un error"} 
        return response
    
@app.route('/items/listaratributovalor', methods=['GET', 'POST']) 
@jsonifiedview
def listarAtributoValor():
    
    """
        metodo que lista los atributos de un item y sus valores
        @param id_item: el id del item al que se asignara el valor del atributo
    """
    
    params = {'GET':request.args, 'POST':request.form}[request.method]
    response  = []
    if not ensureParams(params, ['id_item']): 
        return response
    item= Items.query.filter(Items.id_item ==params['id_item']).first()
    atributos = Atributos.query.filter(Atributos.id_tipo_item == item.id_tipo_item).all()
    for a in atributos:
        atributo = AtributoItem.query.filter(AtributoItem.id_atributo == a.id_atributo).filter(AtributoItem.id_item == item.id_item).filter(AtributoItem.version_item == item.version).first()
        if atributo:
            response.append(atributo) 
        else:
            atributoNuevo = AtributoItem(a.id_atributo, item.id_item, item.version, a.tipo,a.valor)
            response.append(atributoNuevo)
    return response